package com.mjk.common.core.health;

import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.ClusterInfo;
import org.springframework.data.redis.connection.RedisClusterConnection;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisConnectionUtils;
import org.springframework.util.Assert;

import java.util.Properties;

/**
 * redis 健康检测
 */
@Configuration
@ConditionalOnProperty(value="bee.redis",havingValue = "true",matchIfMissing = false)
public class RedisHealthIndicator extends AbstractHealthIndicator {
    private final RedisConnectionFactory redisConnectionFactory;

    public RedisHealthIndicator(RedisConnectionFactory connectionFactory) {
        super("Redis health check failed");
        Assert.notNull(connectionFactory, "ConnectionFactory must not be null");
        this.redisConnectionFactory = connectionFactory;
    }

    protected void doHealthCheck(Health.Builder builder) throws Exception {
        RedisConnection connection = RedisConnectionUtils.getConnection(this.redisConnectionFactory);

        try {
            this.doHealthCheck(builder, connection);
        } finally {
            RedisConnectionUtils.releaseConnection(connection, this.redisConnectionFactory);
        }

    }

    private void doHealthCheck(Health.Builder builder, RedisConnection connection) {
        if (connection instanceof RedisClusterConnection clusterConnection) {
            fromClusterInfo(builder, clusterConnection.clusterGetClusterInfo());
        } else {
            up(builder, connection.serverCommands().info());
        }

    }

    static Health.Builder up(Health.Builder builder, Properties info) {
        builder.withDetail("version", info.getProperty("redis_version"));
        return builder.up();
    }

    static Health.Builder fromClusterInfo(Health.Builder builder, ClusterInfo clusterInfo) {
        builder.withDetail("cluster_size", clusterInfo.getClusterSize());
        builder.withDetail("slots_up", clusterInfo.getSlotsOk());
        builder.withDetail("slots_fail", clusterInfo.getSlotsFail());
        return "fail".equalsIgnoreCase(clusterInfo.getState()) ? builder.down() : builder.up();
    }
}
